package com.qiaofang.collectmanagebff.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qiaofang.collectmanage.stub.bean.*;
import com.qiaofang.collectmanage.stub.feign.client.HouseAgentClient;
import com.qiaofang.collectmanage.stub.feign.client.OperatorLogClient;
import com.qiaofang.collectmanagebff.service.config.ConfigUtils;
import com.qiaofang.collectmanagebff.service.util.DateUtils;
import com.qiaofang.collectmanagebff.service.util.ValidateUtils;
import com.qiaofang.collectmanagebff.service.util.upload.AbstractExcelUploader;
import com.qiaofang.common.constant.CommonResponseCode;
import com.qiaofang.common.util.ConverterBeanUtil;
import com.qiaofang.common.util.JsonUtil;
import com.qiaofang.common.util.LogUtil;
import com.qiaofang.common.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

/**
 * @Author jkc
 * @Date 2017/11/25 下午2:59
 */
@Service
public class UploadHouseAgentServiceImpl extends AbstractExcelUploader {

    private LogUtil logger = LogUtil.getLogger(UploadHouseAgentServiceImpl.class);

    private List<HouseAgentFailDTO> houseAgentFailDTOList = new ArrayList();

    private Map cacheFailHouseAgent = new HashMap();

    @Autowired
    HouseAgentClient houseAgentClient;

    @Autowired
    OperatorLogClient operatorLogClient;


    @Override
    public Map<String, Object> doUpload(InputStream inputStream, Map<String, Object> params) throws Exception {
        //导入开始时间
        Date importTime = new Date();
        //构建失败集合
        houseAgentFailDTOList = new ArrayList();
        Long excelStart = System.currentTimeMillis();
        List<BatchUpdateHouseAgentDTO> excelBatchUpdateHouseAgentSrcDTOS = doExcelResolve(inputStream, params);
        logger.info("解析开始excel结束{}s,大小{}", (System.currentTimeMillis() - excelStart) / 1000, excelBatchUpdateHouseAgentSrcDTOS.size());

        logger.info("去掉手机号重复开始{}", excelBatchUpdateHouseAgentSrcDTOS.size());
        List<BatchUpdateHouseAgentDTO> excelBatchUpdateHouseAgentDTOS = excelBatchUpdateHouseAgentSrcDTOS.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(
                        () -> new TreeSet<>(Comparator.comparing(o -> o.getAgentTelephone()))), ArrayList::new)
        );
        logger.info("去掉手机号重复结束{}", excelBatchUpdateHouseAgentDTOS.size());

        logger.info("判空开始");
        List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTOS = doDataIsBlank(excelBatchUpdateHouseAgentDTOS,houseAgentFailDTOList);
        logger.info("判空结束");

        logger.info("验证合法性开始");
        batchUpdateHouseAgentDTOS = doDataIsValid(batchUpdateHouseAgentDTOS,houseAgentFailDTOList);
        logger.info("验证合法性结束");

        logger.info("房源中介判重开始");
        batchUpdateHouseAgentDTOS = batchHouseAgentRepeat(batchUpdateHouseAgentDTOS,houseAgentFailDTOList);
        logger.info("房源中介判重结束");


        //添加日志
        Long logStart = System.currentTimeMillis();
        logger.info("添加日志开始");
        saveOperatorLog(batchUpdateHouseAgentDTOS.size(), params);
        logger.info("添加日志结束{}s", (System.currentTimeMillis() - logStart) / 1000);

        logger.info("异步开始添加中介开始");
        batchSaveHouseAgentTag(batchUpdateHouseAgentDTOS);
        logger.info("异步开始添加中介结束");

        logger.info("异步开始更新房源中介标识开始");
        batchUpdateHouseAgentTag(batchUpdateHouseAgentDTOS);
        logger.info("异步开始更新房源中介标识结束");


        Map<String, Object> map = new HashMap<>();
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("totalCnt", excelBatchUpdateHouseAgentSrcDTOS.size());
        resultMap.put("totalRepeatCnt", excelBatchUpdateHouseAgentSrcDTOS.size()-excelBatchUpdateHouseAgentDTOS.size());
        resultMap.put("successCnt", batchUpdateHouseAgentDTOS.size());
        resultMap.put("failCnt", excelBatchUpdateHouseAgentDTOS.size() - batchUpdateHouseAgentDTOS.size());
        resultMap.put("importTime", importTime.getTime());
        cacheFailHouseAgent.put(importTime.getTime(), houseAgentFailDTOList);
        map.put("data", resultMap);
        map.put("status", CommonResponseCode.RC_SUCCESS.getResponseCode());
        return map;
    }


    /**
     * 解析sheet 获取原始数据
     *
     * @param inputStream
     * @param params
     * @return
     * @throws Exception
     */
    public List<BatchUpdateHouseAgentDTO> doExcelResolve(InputStream inputStream, Map<String, Object> params) throws Exception {
        List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTOS = new ArrayList();
        Long excelStart = System.currentTimeMillis();
        try(Workbook workBook = WorkbookFactory.create(inputStream)){
            Sheet sheet = workBook.getSheetAt(0);
            logger.info("解析开始excel开始");
            Map<String, Integer> titleMap = new HashMap<>();
            Row firstRow = sheet.getRow(0);
            // 映射 title
            for (int i = firstRow.getFirstCellNum(); i <= firstRow.getLastCellNum(); i++) {
                Cell cell = firstRow.getCell(i);
                String title = getCellValue(cell);
                if (StringUtil.isNotBlank(title)) {
                    titleMap.put(title, i);
                }
            }
            Set<Map.Entry<String, Integer>> set = titleMap.entrySet();
            for (int i = 1; i < sheet.getLastRowNum() + 1; i++) {
                Row row = sheet.getRow(i);
                Iterator<Map.Entry<String, Integer>> titleIterator = set.iterator();
                // 处理导入的单元格数据
                BatchUpdateHouseAgentDTO batchUpdateHouseAgentDTO = processPropertyCellValueExcel(titleIterator, row);
                batchUpdateHouseAgentDTO.setAgentType("V10");
                batchUpdateHouseAgentDTO.setCreatedTime(DateUtils.formatDate(new Date()));
                batchUpdateHouseAgentDTO.setUpdatedTime(DateUtils.formatDate(new Date()));
                batchUpdateHouseAgentDTO.setCreatedUserName((String) params.get("createdUserName"));
                batchUpdateHouseAgentDTO.setUpdatedUserName((String) params.get("createdUserName"));
                if (StringUtils.isNotEmpty(batchUpdateHouseAgentDTO.getAgentTelephone())
                        || StringUtils.isNotBlank(batchUpdateHouseAgentDTO.getAgentUserName())) {
                    batchUpdateHouseAgentDTOS.add(batchUpdateHouseAgentDTO);
                }
            }
        }
        logger.info("解析开始excel结束{}s", (System.currentTimeMillis() - excelStart) / 1000);
        return batchUpdateHouseAgentDTOS;
    }


    /**
     * 判断手机号是否为空
     *
     * @throws Exception
     * @returnhouseAgentFailDTOList
     */
    public List<BatchUpdateHouseAgentDTO> doDataIsBlank(List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTOS,List<HouseAgentFailDTO> houseAgentFailDTOList) throws Exception {
        batchUpdateHouseAgentDTOS = batchUpdateHouseAgentDTOS.stream().filter(batchUpdateHouseAgentDTO -> isTelephoneBlank(batchUpdateHouseAgentDTO,houseAgentFailDTOList)).collect(Collectors.toList());
        return batchUpdateHouseAgentDTOS;
    }

    /**
     * 判断手机号是否合法
     *
     * @return
     * @throws Exception
     */
    public List<BatchUpdateHouseAgentDTO> doDataIsValid(List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTOS,List<HouseAgentFailDTO> houseAgentFailDTOList) throws Exception {
        batchUpdateHouseAgentDTOS = batchUpdateHouseAgentDTOS.stream().filter(batchUpdateHouseAgentDTO -> isMobile(batchUpdateHouseAgentDTO,houseAgentFailDTOList)).collect(Collectors.toList());
        return batchUpdateHouseAgentDTOS;
    }

    /**
     * 校验手机号
     * @return 校验通过返回true，否则返回false
     */
    public boolean isMobile(BatchUpdateHouseAgentDTO batchUpdateHouseAgentDTO,List<HouseAgentFailDTO> houseAgentFailDTOList) {
        boolean flag = false;
        String phone = batchUpdateHouseAgentDTO.getAgentTelephone();
        if(StringUtils.isNotEmpty(phone)){
            phone = phone.trim();
            if (phone.length() == 11) {
                Matcher m = p.matcher(phone);
                boolean isMatch = m.matches();
                if (isMatch) {
                    flag = true;
                } else {
                    HouseAgentFailDTO houseAgentFailDTO = getHouseAgentFailDTO(batchUpdateHouseAgentDTO, "手机号格式不对");
                    houseAgentFailDTOList.add(houseAgentFailDTO);
                }
            } else {
                HouseAgentFailDTO houseAgentFailDTO = getHouseAgentFailDTO(batchUpdateHouseAgentDTO, "手机号格式不对");
                houseAgentFailDTOList.add(houseAgentFailDTO);
            }
        }
        return flag;
    }


    /**
     * 判断手机号是否为空
     * @return
     */
    public boolean isTelephoneBlank(BatchUpdateHouseAgentDTO batchUpdateHouseAgentDTO,List<HouseAgentFailDTO> houseAgentFailDTOList) {
        if (batchUpdateHouseAgentDTO.getAgentTelephone() == null || "".equals(batchUpdateHouseAgentDTO.getAgentTelephone())) {
            HouseAgentFailDTO houseAgentFailDTO = getHouseAgentFailDTO(batchUpdateHouseAgentDTO, "手机号不能为空");
            houseAgentFailDTOList.add(houseAgentFailDTO);
            return false;
        }
        return true;
    }

    /**
     * 判断中介号码重复
     *
     * @param batchUpdateHouseAgentDTO
     * @return
     */
    public BatchUpdateHouseAgentDTO houseAgentHadRepeat(BatchUpdateHouseAgentDTO batchUpdateHouseAgentDTO) {
        HouseAgentFailDTO houseAgentFailDTO = getHouseAgentFailDTO(batchUpdateHouseAgentDTO, "中介号码重复");
        houseAgentFailDTOList.add(houseAgentFailDTO);
        return batchUpdateHouseAgentDTO;
    }

    public HouseAgentFailDTO getHouseAgentFailDTO(BatchUpdateHouseAgentDTO batchUpdateHouseAgentDTO, String msg) {
        HouseAgentFailDTO houseAgentFailDTO = new HouseAgentFailDTO();
        JSONObject rowObject = new JSONObject();
        houseAgentFailDTO.setAgentUserName(batchUpdateHouseAgentDTO.getAgentUserName());
        rowObject.put(SYS_PRO_TITLE_HOUSE_AGENT_NAME, batchUpdateHouseAgentDTO.getAgentUserName());
        rowObject.put(SYS_PRO_TITLE_HOUSE_AGENT_TEL, batchUpdateHouseAgentDTO.getAgentTelephone());
        houseAgentFailDTO.setAgentTelephone(batchUpdateHouseAgentDTO.getAgentTelephone());
        houseAgentFailDTO.setImportTitle(JsonUtil.toJson(SYS_PRO_TITLE_HOUSE_AGENT));
        houseAgentFailDTO.setImportValue(rowObject.toJSONString());
        houseAgentFailDTO.setErrorMsg(msg);
        houseAgentFailDTO.setFailMsg(msg);
        return houseAgentFailDTO;
    }

    /**
     * 分批判定房源是否重复
     *
     * @param batchUpdateHouseAgentDTOS
     */
    public List<BatchUpdateHouseAgentDTO> batchHouseAgentRepeat(List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTOS,List<HouseAgentFailDTO> houseAgentFailDTOList) {
        List<BatchGetHouseAgentRepeatDTO> isRepeatHouseAgentList = new ArrayList<>();
        if (batchUpdateHouseAgentDTOS.size() != 0) {
            logger.info("分批判定房源是否重复{}", batchUpdateHouseAgentDTOS.size());
            Long startUpdateHouseAgentTime = System.currentTimeMillis();
            int batchNum = ConfigUtils.getBatchCount();
            for (int j = 0; j < batchUpdateHouseAgentDTOS.size() / batchNum + 1; j++) {
                List<BatchUpdateHouseAgentDTO> mEndLists = new ArrayList<>();
                mEndLists = getBatchByNum(mEndLists,j,batchNum,batchUpdateHouseAgentDTOS);
                List<BatchGetHouseAgentRepeatDTO> batchGetHouseAgentRepeatDTOs = houseAgentClient.batchGetHouseAgentRepeat(mEndLists);
                isRepeatHouseAgentList.addAll(batchGetHouseAgentRepeatDTOs);
            }

            List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTORepeat = new ArrayList<>();
            ConverterBeanUtil.copyListBeanPropertiesToList(isRepeatHouseAgentList, batchUpdateHouseAgentDTORepeat, BatchUpdateHouseAgentDTO.class);

            //记录重复数据信息
            batchUpdateHouseAgentDTORepeat.stream().map(batchUpdateHouseAgentDTO -> houseAgentHadRepeat(batchUpdateHouseAgentDTO)).collect(Collectors.toList());

            // 差集 提取出不包含重复手机号的
            batchUpdateHouseAgentDTOS = batchUpdateHouseAgentDTOS.stream().filter(item -> !batchUpdateHouseAgentDTORepeat.contains(item)).collect(Collectors.toList());

            logger.info("分批判定房源是否重复结束" + (System.currentTimeMillis() - startUpdateHouseAgentTime) / 1000 + "s 大小"+batchUpdateHouseAgentDTOS.size());
        }
        return batchUpdateHouseAgentDTOS;
    }

    /**
     * 分批获取房源中介数据
     * @param mEndLists
     * @param j
     * @param batchNum
     * @param batchUpdateHouseAgentDTOS
     * @return
     */
    public  List<BatchUpdateHouseAgentDTO> getBatchByNum(List<BatchUpdateHouseAgentDTO> mEndLists,int j,int batchNum,List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTOS){
        if ((j * batchNum + batchNum) < batchUpdateHouseAgentDTOS.size()) {
            mEndLists = batchUpdateHouseAgentDTOS.subList(j * batchNum, j * batchNum + batchNum);
        } else if ((j * batchNum + batchNum) > batchUpdateHouseAgentDTOS.size()) {
            mEndLists = batchUpdateHouseAgentDTOS.subList(j * batchNum, batchUpdateHouseAgentDTOS.size());
        } else if (batchUpdateHouseAgentDTOS.size() < batchNum) {
            mEndLists = batchUpdateHouseAgentDTOS.subList(0, batchUpdateHouseAgentDTOS.size());
        }else if(batchUpdateHouseAgentDTOS.size() == batchNum){
            mEndLists = batchUpdateHouseAgentDTOS.subList(0, batchUpdateHouseAgentDTOS.size()-1);
        }
        return mEndLists;
    }


    /**
     * 批量更新房源中介标识
     *
     * @param batchUpdateHouseAgentDTOS
     */
    public void batchUpdateHouseAgentTag(List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTOS) {
        if (batchUpdateHouseAgentDTOS.size() != 0) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    logger.info("批量更新房源中介标识,大小{}", batchUpdateHouseAgentDTOS.size());
                    Long startUpdateHouseAgentTime = System.currentTimeMillis();
                    int batchNum = ConfigUtils.getBatchCount();
                    for (int j = 0; j < batchUpdateHouseAgentDTOS.size() / batchNum + 1; j++) {
                        List<BatchUpdateHouseAgentDTO> mEndLists = new ArrayList<>();
                        mEndLists = getBatchByNum(mEndLists,j,batchNum,batchUpdateHouseAgentDTOS);
                        houseAgentClient.batchUpdateHouseAgent(mEndLists);
                    }
                    logger.info("批量更新中介标识结束" + (System.currentTimeMillis() - startUpdateHouseAgentTime) / 1000 + "s");
                }
            }).start();
        }
    }

    /**
     * //批量添加中介信息
     *
     * @param batchUpdateHouseAgentDTOS
     */
    public void batchSaveHouseAgentTag(List<BatchUpdateHouseAgentDTO> batchUpdateHouseAgentDTOS) {
        if (batchUpdateHouseAgentDTOS.size() != 0) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Long batchAddHouseAgentTime = System.currentTimeMillis();
                    logger.info("批量添加中介信息开始,大小{}", batchUpdateHouseAgentDTOS.size());
                    int batchNum = ConfigUtils.getBatchCount();
                    for (int j = 0; j < batchUpdateHouseAgentDTOS.size() / batchNum + 1; j++) {
                        List<BatchUpdateHouseAgentDTO> mEndLists = new ArrayList<>();
                        mEndLists = getBatchByNum(mEndLists,j,batchNum,batchUpdateHouseAgentDTOS);
                        houseAgentClient.batchSaveHouseAgent(mEndLists);
                    }
                    logger.info("批量添加中介信息结束{}s", (System.currentTimeMillis() - batchAddHouseAgentTime) / 1000);

                }
            }).start();
        }
    }


    /**
     * 保存日志
     *
     * @param successCnt
     */
    public void saveOperatorLog(int successCnt, Map para) {
        List<SaveOperatorLogDTO> saveOperatorLogDTOs = new ArrayList<>();
        SaveOperatorLogDTO saveOperatorLogDTO = new SaveOperatorLogDTO();
        saveOperatorLogDTO.setLogUuid(UUID.randomUUID().toString());
        saveOperatorLogDTO.setOperatorType("HOUSEAGENT");
        saveOperatorLogDTO.setCreatedUserName((String) para.get("createdUserName"));
        saveOperatorLogDTO.setCreatedTime(DateUtils.formatDate(new Date()));
        saveOperatorLogDTO.setContent("导入" + successCnt + "条号码");
        saveOperatorLogDTOs.add(saveOperatorLogDTO);
        operatorLogClient.batchSaveOperatorLog(saveOperatorLogDTOs);
    }

    /**
     * 获取单元格数据
     *
     * @param cell
     * @return
     */
    public String getCellValue(Cell cell) {
        String result = null;
        if (cell == null) {
            return null;
        }
        switch (cell.getCellType()) {
            case Cell.CELL_TYPE_NUMERIC:
                result = StringUtil.convertDoubleToString(cell.getNumericCellValue());
                if (StringUtil.isNotEmpty(result)) {
                    if (result.indexOf(StringUtil.STR_DOT) != -1) {
                        if (Long.valueOf(result.substring(result.indexOf(StringUtil.STR_DOT) + 1)).longValue() == 0L) {
                            result = result.substring(0, result.indexOf(StringUtil.STR_DOT));
                        }
                    }
                }
                break;
            case Cell.CELL_TYPE_STRING:
                result = StringUtil.getTrimString(cell.getStringCellValue());
                break;
            case Cell.CELL_TYPE_BOOLEAN:
                result = StringUtil.getString(cell.getBooleanCellValue());
                break;
            case HSSFCell.CELL_TYPE_BLANK:
                result = "";
                break;
            default:
                result = "";
                break;
        }
        return result;
    }

    /**
     * 解析excel获取每条数据
     *
     * @param titleIterator
     * @param row
     * @return
     */
    private BatchUpdateHouseAgentDTO processPropertyCellValueExcel(Iterator<Map.Entry<String, Integer>> titleIterator, Row row) {

        BatchUpdateHouseAgentDTO batchUpdateHouseAgentDTO = new BatchUpdateHouseAgentDTO();
        while (titleIterator.hasNext()) {
            Map.Entry<String, Integer> entry = titleIterator.next();
            String excelTitle = entry.getKey();
            Integer cellIndex = entry.getValue();
            if (row != null) {
                String cellValue = getCellValue(row.getCell(cellIndex));
                if (excelTitle.equals(SYS_PRO_TITLE_HOUSE_AGENT_NAME)) {
                    batchUpdateHouseAgentDTO.setAgentUserName(cellValue);
                }
                if (excelTitle.equals(SYS_PRO_TITLE_HOUSE_AGENT_TEL)) {
                    batchUpdateHouseAgentDTO.setAgentTelephone(ValidateUtils.replaceBlank(cellValue));
                }
            }
        }
        return batchUpdateHouseAgentDTO;
    }

    public Map<String, Integer> createTitleCell(Sheet sheet, HouseAgentFailDTO importHistory) {
        Map<String, Integer> map = new HashMap<String, Integer>();
        Row rowTitle = sheet.createRow(0);
        Cell failCell = rowTitle.createCell(0);
        failCell.setCellValue("错误信息");
        map.put("错误信息", 0);
        JSONArray jsonArray = JSON.parseArray(importHistory.getImportTitle());
        for (int i = 0; i < jsonArray.size(); i++) {
            Cell cell = rowTitle.createCell((i + 1));
            cell.setCellValue(jsonArray.getString(i));
            map.put(jsonArray.getString(i), (i + 1));
        }
        return map;
    }

    public void createDataCell(List<HouseAgentFailDTO> list, Sheet sheet, Map<String, Integer> titleMap) {
        for (int i = 0; i < list.size(); i++) {
            HouseAgentFailDTO history = list.get(i);
            JSONObject jsonObject = JSON.parseObject(history.getImportValue());
            Row row = sheet.createRow(i + 1);  // 数据从第二行开始,第二行的rowIndex为1
            Set<Map.Entry<String, Integer>> titleEntry = titleMap.entrySet();
            Iterator<Map.Entry<String, Integer>> it = titleEntry.iterator();
            while (it.hasNext()) {
                Map.Entry<String, Integer> entry = it.next();
                Cell cell = row.createCell(entry.getValue());
                if (entry.getValue().intValue() == 0) {
                    cell.setCellValue(history.getFailMsg());
                } else {
                    cell.setCellValue(StringUtil.getString(jsonObject.get(entry.getKey())));
                }
            }
        }
    }


    @Override
    public void downloadFailureData(Long importDate, HttpServletResponse response) throws Exception {
        Workbook workbook = createDefaultXssfWorkbook();
        Sheet sheet = workbook.createSheet();
        List<HouseAgentFailDTO> houseAgentFailDTOList = (List<HouseAgentFailDTO>) cacheFailHouseAgent.get(importDate);
        if (houseAgentFailDTOList != null && houseAgentFailDTOList.size() > 0) {
            cacheFailHouseAgent.clear();
            cacheFailHouseAgent.put(importDate,houseAgentFailDTOList);
            // 创建标题行
            Map<String, Integer> titleMap = createTitleCell(sheet, houseAgentFailDTOList.get(0));
            // 创建数据行
            createDataCell(houseAgentFailDTOList, sheet, titleMap);
        }
        writeExcel(response, workbook, "失败导入结果.xlsx");
    }
}
